package xyz.syyrjx.blog.util.ai;


import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import xyz.syyrjx.blog.entity.ai.AiDialogue;
import xyz.syyrjx.blog.entity.ai.chat.ChatMessage;
import xyz.syyrjx.blog.entity.ai.chat.ChatRequest;
import xyz.syyrjx.blog.entity.ai.chat.ChatResponse;
import xyz.syyrjx.blog.entity.ai.chat.Delta;
import xyz.syyrjx.blog.exception.AiException;
import xyz.syyrjx.blog.util.CachePool;
import xyz.syyrjx.blog.util.ConstValuePool;
import xyz.syyrjx.blog.util.StringUtil;
import xyz.syyrjx.blog.websocket.AiWebsocketService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;


/**
 * @author 大地崩坏苍蝇兽
 * @date 2024/2/18 12:54
 * @description chatgpt模型服务
 * @since v0.0.1
 */
@Component
public class ChatGptModelService implements AiModelService{

    private static final Logger logger = LoggerFactory.getLogger(ChatGptModelService.class);

    @Value("${openai.chatgtp.api.url}")
    private String uri;

    @Value(("${openai.chatgtp.model}"))
    private String model;

    @Resource
    private AiWebsocketService aiWebsocketService;

    @Override
    public String answer(String prompt, HttpServletRequest request, String identity) throws InterruptedException {

        // 获取历史对话列表，chatMessages实现连续对话、chatDialogues便于页面显示
        List<AiDialogue> chatDialogues = CachePool.AI_DIALOGUE_LIST_MAP.get(identity)
                .computeIfAbsent(ConstValuePool.CHAT_DIALOGUES, k -> new LinkedList<>());
        List<ChatMessage> chatMessages = CachePool.CHAT_MESSAGE_DIALOGUES_MAP.get(identity);
        if (chatMessages == null) {
            chatMessages = new ArrayList<>();
            chatMessages.add(ChatMessage.createSystemDialogue("You are a helpful assistant."));
            CachePool.CHAT_MESSAGE_DIALOGUES_MAP.put(identity, chatMessages);
        }

        chatMessages.add(new ChatMessage("user", prompt));
        chatDialogues.add(AiDialogue.createUserDialogue(prompt));

        ChatRequest chatRequest = new ChatRequest(this.model, chatMessages);
        logger.debug("发送的请求为：{}",chatRequest);
        // 获取代理openai客户端，发送请求
        WebClient aProxyOpenaiClient = ConstValuePool.getAProxyOpenaiClient();
        Flux<String> chatResponseFlux = aProxyOpenaiClient
                .post()
                .uri(uri)
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(chatRequest.toString())
                .retrieve() // Initiate the request
                .bodyToFlux(String.class);// Specify the type of the response body

        StringBuilder resultBuilder = new StringBuilder();
        // 设置同步信号量
        Semaphore semaphore = new Semaphore(0);
        chatResponseFlux.subscribe(
                value -> {
                    logger.debug("返回结果：{}", value);
                    if ("[DONE]".equals(value)) {
                        return;
                    }
                    try {
                        ChatResponse chatResponse = ConstValuePool.OBJECT_MAPPER.readValue(value, ChatResponse.class);
                        List<ChatResponse.Choice> choices = chatResponse.getChoices();
                        ChatResponse.Choice choice = choices.get(choices.size() - 1);
                        Delta delta = choice.getDelta();
                        String res = delta.getContent();
                        if (res != null) {
                            StringBuilder finalResultBuilder = resultBuilder.append(res);
                            if (1 == (1 & StringUtil.countSubStr(finalResultBuilder,ConstValuePool.MARKDOWN_CODE_BLOCK_START))) {
                                finalResultBuilder = new StringBuilder(finalResultBuilder)
                                        .append(ConstValuePool.MARKDOWN_CODE_BLOCK_END);
                            }
                            aiWebsocketService.sendMessage(finalResultBuilder.toString(), identity);
                        }
                    } catch (JsonProcessingException e) {
                        logger.error("chatgpt解析出错：{}",e.toString());
                        throw new AiException("chatgpt运行出错",e);
                    }
                }, // 获得数据，拼接结果，发送给前端
                error -> {
                        semaphore.release();
                        logger.error("chatgpt执行出错，报错调用栈如下");
                        while (error != null) {
                            logger.error(error.toString());
                            error = error.getCause();
                        }
                    }, // 失败释放信号量，并报错
                semaphore::release// 成功释放信号量
        );
        semaphore.acquire();
        // 释放openai客户端
        ConstValuePool.PROXY_OPENAI_CLIENT_FREE.add(aProxyOpenaiClient);
        String resString = resultBuilder.toString();
        logger.debug(resString);

        chatDialogues.add(AiDialogue.createAssistantDialogue(resString));
        chatMessages.add(ChatMessage.createAssistantDialogue(resString));

        // 对话轮数过多删除最早的历史对话，避免大量消耗tokens
        while (chatMessages.size() > ConstValuePool.CHAT_MAX_MESSAGE
        || !"user".equals(chatMessages.get(1).getRole())) {
            chatMessages.remove(1);
        }
        AiLogUtil.logDialogues(logger,"chatpgt",prompt,resString,request);

        return "";
    }
}
